//===- LoongArchInstrFormats.td - LoongArch Instr. Formats -*- tablegen -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
//  Describe LoongArch instructions format
//
//  opcode       - operation code.
//  rd           - destination register operand.
//  r{j/k}       - source register operand.
//  immN         - immediate data operand.
//
//===----------------------------------------------------------------------===//

class LAInst<dag outs, dag ins, string opcstr, string opnstr,
             list<dag> pattern = []>
    : Instruction {
  field bits<32> Inst;
  // SoftFail is a field the disassembler can use to provide a way for
  // instructions to not match without killing the whole decode process. It is
  // mainly used for ARM, but Tablegen expects this field to exist or it fails
  // to build the decode table.
  field bits<32> SoftFail = 0;

  let Namespace = "LoongArch";
  let Size = 4;
  let OutOperandList = outs;
  let InOperandList = ins;
  let AsmString = opcstr # "\t" # opnstr;
  let Pattern = pattern;
}

// Pseudo instructions
class Pseudo<dag outs, dag ins, list<dag> pattern = [], string opcstr = "",
             string opnstr = "">
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  let isPseudo = 1;
  let isCodeGenOnly = 1;
}

// 2R-type
// <opcode | rj | rd>
class Fmt2R<bits<22> op, dag outs, dag ins, string opcstr, string opnstr,
            list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<5> rj;
  bits<5> rd;

  let Inst{31-10} = op;
  let Inst{9-5} = rj;
  let Inst{4-0} = rd;
}

// 3R-type
// <opcode | rk | rj | rd>
class Fmt3R<bits<17> op, dag outs, dag ins, string opcstr, string opnstr,
            list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<5> rk;
  bits<5> rj;
  bits<5> rd;

  let Inst{31-15} = op;
  let Inst{14-10} = rk;
  let Inst{9-5} = rj;
  let Inst{4-0} = rd;
}

// 3RI2-type
// <opcode | I2 | rk | rj | rd>
class Fmt3RI2<bits<15> op, dag outs, dag ins, string opcstr, string opnstr,
              list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<2> imm2;
  bits<5> rk;
  bits<5> rj;
  bits<5> rd;

  let Inst{31-17} = op;
  let Inst{16-15} = imm2;
  let Inst{14-10} = rk;
  let Inst{9-5} = rj;
  let Inst{4-0} = rd;
}

// 3RI3-type
// <opcode | I3 | rk | rj | rd>
class Fmt3RI3<bits<14> op, dag outs, dag ins, string opcstr, string opnstr,
              list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<3> imm3;
  bits<5> rk;
  bits<5> rj;
  bits<5> rd;

  let Inst{31-18} = op;
  let Inst{17-15} = imm3;
  let Inst{14-10} = rk;
  let Inst{9-5} = rj;
  let Inst{4-0} = rd;
}

// 2RI5-type
// <opcode | I5 | rj | rd>
class Fmt2RI5<bits<17> op, dag outs, dag ins, string opcstr, string opnstr,
              list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<5> imm5;
  bits<5> rj;
  bits<5> rd;

  let Inst{31-15} = op;
  let Inst{14-10} = imm5;
  let Inst{9-5} = rj;
  let Inst{4-0} = rd;
}

// 2RI6-type
// <opcode | I6 | rj | rd>
class Fmt2RI6<bits<16> op, dag outs, dag ins, string opcstr, string opnstr,
              list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<6> imm6;
  bits<5> rj;
  bits<5> rd;

  let Inst{31-16} = op;
  let Inst{15-10} = imm6;
  let Inst{9-5} = rj;
  let Inst{4-0} = rd;
}

// 2RI8-type
// <opcode | I8 | rj | rd>
class Fmt2RI8<bits<14> op, dag outs, dag ins, string opcstr, string opnstr,
              list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<8> imm8;
  bits<5> rj;
  bits<5> rd;

  let Inst{31-18} = op;
  let Inst{17-10} = imm8;
  let Inst{9-5} = rj;
  let Inst{4-0} = rd;
}

// 2RI12-type
// <opcode | I12 | rj | rd>
class Fmt2RI12<bits<10> op, dag outs, dag ins, string opcstr, string opnstr,
               list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<12> imm12;
  bits<5> rj;
  bits<5> rd;

  let Inst{31-22} = op;
  let Inst{21-10} = imm12;
  let Inst{9-5} = rj;
  let Inst{4-0} = rd;
}

// 2RI14-type
// <opcode | I14 | rj | rd>
class Fmt2RI14<bits<8> op, dag outs, dag ins, string opcstr, string opnstr,
               list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<14> imm14;
  bits<5> rj;
  bits<5> rd;

  let Inst{31-24} = op;
  let Inst{23-10} = imm14;
  let Inst{9-5} = rj;
  let Inst{4-0} = rd;
}

// 2RI16-type
// <opcode | I16 | rj | rd>
class Fmt2RI16<bits<6> op, dag outs, dag ins, string opcstr, string opnstr,
               list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<16> imm16;
  bits<5> rj;
  bits<5> rd;

  let Inst{31-26} = op;
  let Inst{25-10} = imm16;
  let Inst{9-5} = rj;
  let Inst{4-0} = rd;
}

// 1RI20-type
// <opcode | I20 | rd>
class Fmt1RI20<bits<7> op, dag outs, dag ins, string opcstr, string opnstr,
               list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<20> imm20;
  bits<5> rd;

  let Inst{31-25} = op;
  let Inst{24-5} = imm20;
  let Inst{4-0} = rd;
}

// 1RI21-type
// <opcode | I21[15:0] | rj | I21[20:16]>
class Fmt1RI21<bits<6> op, dag outs, dag ins, string opcstr, string opnstr,
               list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<21> imm21;
  bits<5> rj;

  let Inst{31-26} = op;
  let Inst{25-10} = imm21{15-0};
  let Inst{9-5} = rj;
  let Inst{4-0} = imm21{20-16};
}

// I15-type
// <opcode | I15>
class FmtI15<bits<17> op, dag outs, dag ins, string opcstr, string opnstr,
             list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<15> imm15;

  let Inst{31-15} = op;
  let Inst{14-0} = imm15;
}

// I26-type
// <opcode | I26[15:0] | I26[25:16]>
class FmtI26<bits<6> op, dag outs, dag ins, string opcstr, string opnstr,
             list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<26> imm26;

  let Inst{31-26} = op;
  let Inst{25-10} = imm26{15-0};
  let Inst{9-0} = imm26{25-16};
}

// FmtBSTR_W
// <opcode[11:1] | msbw | opcode[0] | lsbw | rj | rd>
class FmtBSTR_W<bits<12> op, dag outs, dag ins, string opcstr, string opnstr,
                list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<5> msbw;
  bits<5> lsbw;
  bits<5> rj;
  bits<5> rd;

  let Inst{31-21} = op{11-1};
  let Inst{20-16} = msbw;
  let Inst{15} = op{0};
  let Inst{14-10} = lsbw;
  let Inst{9-5} = rj;
  let Inst{4-0} = rd;
}

// FmtBSTR_D
// <opcode | msbd | lsbd | rj | rd>
class FmtBSTR_D<bits<10> op, dag outs, dag ins, string opcstr, string opnstr,
                list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<6> msbd;
  bits<6> lsbd;
  bits<5> rj;
  bits<5> rd;

  let Inst{31-22} = op;
  let Inst{21-16} = msbd;
  let Inst{15-10} = lsbd;
  let Inst{9-5} = rj;
  let Inst{4-0} = rd;
}

// FmtASRT
// <opcode | rk | rj | 0x0>
class FmtASRT<bits<17> op, dag outs, dag ins, string opcstr, string opnstr,
              list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<5> rk;
  bits<5> rj;

  let Inst{31-15} = op;
  let Inst{14-10} = rk;
  let Inst{9-5} = rj;
  let Inst{4-0} = 0x0;
}

// FmtPRELD
// < 0b0010101011 | I12 | rj | I5>
class FmtPRELD<dag outs, dag ins, string opcstr, string opnstr,
               list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<12> imm12;
  bits<5> rj;
  bits<5> imm5;

  let Inst{31-22} = 0b0010101011;
  let Inst{21-10} = imm12;
  let Inst{9-5} = rj;
  let Inst{4-0} = imm5;
}

// FmtPRELDX
// < 0b00111000001011000 | rk | rj | I5>
class FmtPRELDX<dag outs, dag ins, string opcstr, string opnstr,
                list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<5> rk;
  bits<5> rj;
  bits<5> imm5;

  let Inst{31-15} = 0b00111000001011000;
  let Inst{14-10} = rk;
  let Inst{9-5} = rj;
  let Inst{4-0} = imm5;
}

// FmtCSR
// <opcode[12:5] | csr_num | opcode[4:0] | rd>
class FmtCSR<bits<13> op, dag outs, dag ins, string opcstr, string opnstr,
             list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<14> csr_num;
  bits<5> rd;

  let Inst{31-24} = op{12-5};
  let Inst{23-10} = csr_num;
  let Inst{9-5} = op{4-0};
  let Inst{4-0} = rd;
}

// FmtCSRXCHG
// <opcode | csr_num | rj | rd>
class FmtCSRXCHG<bits<8> op, dag outs, dag ins, string opcstr, string opnstr,
                 list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<14> csr_num;
  bits<5> rj;
  bits<5> rd;

  let Inst{31-24} = op;
  let Inst{23-10} = csr_num;
  let Inst{9-5} = rj;
  let Inst{4-0} = rd;
}

// FmtCACOP
// <0b0000011000 | I12 | rj | I5>
class FmtCACOP<dag outs, dag ins, string opcstr, string opnstr,
               list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<12> imm12;
  bits<5> rj;
  bits<5> op;

  let Inst{31-22} = 0b0000011000;
  let Inst{21-10} = imm12;
  let Inst{9-5} = rj;
  let Inst{4-0} = op;
}

// FmtIMM32
// <I32>
class FmtI32<bits<32> op, string opstr, list<dag> pattern = []>
    : LAInst<(outs), (ins), opstr, "", pattern> {
  let Inst{31-0} = op;
}

// FmtINVTLB
// <0b00000110010010011 | rk | rj | I5>
class FmtINVTLB<dag outs, dag ins, string opcstr, string opnstr,
                list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<5> rk;
  bits<5> rj;
  bits<5> op;

  let Inst{31-15} = 0b00000110010010011;
  let Inst{14-10} = rk;
  let Inst{9-5} = rj;
  let Inst{4-0} = op;
}

// FmtLDPTE
// <0b00000110010001 | seq | rj | 00000>
class FmtLDPTE<dag outs, dag ins, string opcstr, string opnstr,
               list<dag> pattern = []>
    : LAInst<outs, ins, opcstr, opnstr, pattern> {
  bits<8> seq;
  bits<5> rj;

  let Inst{31-18} = 0b00000110010001;
  let Inst{17-10} = seq;
  let Inst{9-5} = rj;
  let Inst{4-0} = 0b00000;
}
